#!/usr/bin/python2.4
# jhebert@cs.washington.edu

import Queue

class VirtualNode:
  """ This class represents a virtual node.
  It follows the same interface as chart and program nodes.
  It currently supports channel renaming by listening for a set
  of values and emitting their translation. """

  def __init__(self, cr, name):
    # The chartRunner managing this node.
    self.runners = [cr]
    self.runnableQueue = Queue.Queue()
    self.nodeName = name
    # Maps a name to a set of names.
    self.translateTable = {}
    # Set of values being listened for. (Used by self.runner)
    self.borderInputs = {}

  ## <Called from chartParser> ##

  def AddTranslation(self, fromName, toName):
    """ Add a translation to the current set. """
    self.borderInputs[fromName] = None
    if(fromName in self.translateTable):
      self.translateTable[fromName].append(toName)
    else:
      self.translateTable[fromName] = [toName]

  ## <Called from chartParser> ##
  ## <Called from chartRunner> ##

  def IsListeningFor(self, varName):
    """ Is this programNode listening for varName. """
    return (varName in self.translateTable)

  def Emit(self, caller, varName, varValue):
    """ Add a variable to dataStruct holding waiting values. """
    for name in self.translateTable[varName]:
      self.runnableQueue.put((name, varValue))

  def Run(self):
    """ If ready to run grab the appropriate variables and
    emit them out immediately to the chartRunner.
    Could almost emit these immediately upon receipt.
    Emit calls are non-blocking, so would be fairly safe."""
    if(self.runnableQueue.empty()):
      return
    argName, argValue = self.runnableQueue.get(False)
    for runner in self.runners:
      runner.Emit(self.nodeName, argName, argValue)

  def ReadyToRun(self):
    """ Determines if the list of translations to emit is empty
    or not. Return true if some variables are ready to run. """
    return not(self.runnableQueue.empty())

  ## <End of called from chartRunner> ##
